<?php abstract class Daemon {
	protected static $Detached = FALSE; // is the daemon detached from console at the moment
	protected static $LogLevel = 4; // syslog level
	protected static $PidFile = '/var/run/overwatch/antlion.pid'; // pidfile name

	public static function Summon ($LogLevel, $User = '', $Group = '') {
		self::$LogLevel = $LogLevel;
		if (defined ('App::NAME')) {
			$App = constant ('App::NAME');
		} else {
			$App = FALSE;
		}
		openlog ($App, LOG_PID, LOG_DAEMON);
		if (strlen ($Group)) {
			if ($Group === (string) (int) $Group) {
				$Group = posix_getgrgid ((int) $Group);
			} else {
				$Group = posix_getgrnam ($Group);
			}
			$Group = $Group ['gid'];
			if ($Group !== ($CurGroup = posix_getgid ())) {
				if (posix_setgid ($Group)) {
					self::Debug (M__D_CONF_CHXID_OK, 'GID', $Group);
				} else {
					self::Warn (M__D_CONF_CHXID_ERR, 'GID', $Group, $CurGroup);
				}
			} else {
				self::Debug (M__D_CONF_CHXID_NO, 'GID', $Group);
			}
		}
		if (strlen ($User)) {
			if ($User === (string) (int) $User) {
				$User = posix_getpwuid ((int) $User);
			} else {
				$User = posix_getpwnam ($User);
			}
			$User = $User ['uid'];
			if ($User !== ($CurUser = posix_getuid ())) {
				if (posix_setuid ($User)) {
					self::Debug (M__D_CONF_CHXID_OK, 'UID', $User);
				} else {
					self::Warn (M__D_CONF_CHXID_ERR, 'UID', $User, $CurUser);
				}
			} else {
				self::Debug (M__D_CONF_CHXID_NO, 'UID', $User);
			}
		}
	}
	public static function Banish () {
		if (file_exists (self::$PidFile) and ! @unlink (self::$PidFile)) {
			self::Warn (M__D_PID_REMOVE_ERR, self::$PidFile);
		}
	}
	public static function Detach () {
		self::Debug (M__D_FORK_INIT);
		switch (pcntl_fork ()) {
			default:
				exit (0);
			case -1:
				self::Warn (M__D_FORK_ERR);
				return (NULL);
			case 0:
				ini_set ('display_errors', 0);
				ini_set ('log_errors', 1);
				ini_set ('error_log', 'syslog');
				posix_setsid ();
				self::$Detached = TRUE;
				fclose (STDIN);
				fclose (STDOUT);
				fclose (STDERR);
				$R = @file_put_contents (self::$PidFile, ($Pid = getmypid ())."\n");
				if (FALSE === $R) {
					self::Warn (M__D_PID_CREATE_ERR, $Pid, self::$PidFile);
				} else {
					self::Debug (M__D_PID_CREATE_OK, $Pid, self::$PidFile, $Result);
				}
				self::Debug (M__D_FORK_OK);
		}
	}

	protected static function Log ($Level, array $Args) {
		if ($Level > self::$LogLevel) {
			return (NULL);
		}
		$Message = explode ("\n", call_user_func_array ('sprintf', $Args));
		foreach ($Message as $Line) {
			if (self::$Detached) {
				syslog ($Level, $Line);
			} else {
				fputs (STDERR, "($Level) $Line\n");
			}
		}
	}
	public static function Debug ($Tpl) {
		$Args = func_get_args ();
		self::Log (LOG_DEBUG, $Args);
	}
	public static function Info ($Tpl) {
		$Args = func_get_args ();
		self::Log (LOG_INFO, $Args);
	}
	public static function Notice ($Tpl) {
		$Args = func_get_args ();
		self::Log (LOG_NOTICE, $Args);
	}
	public static function Warn ($Tpl) {
		$Args = func_get_args ();
		self::Log (LOG_WARNING, $Args);
	}
	public static function Error ($Tpl) {
		$Args = func_get_args ();
		self::Log (LOG_ERR, $Args);
		exit (255);
	}
} ?>